﻿

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using Conference.Core.DL;
using Conference.Core.Dl;
using Conference.Core.SL;
using Conference.Core.Sal.DataContracts;
using Conference.Core.Sal.DataRequests;
using TeaLightV5.Foundation.BL;
using TeaLightV5.Foundation.BL.Sync;
using TeaLightV5.Foundation.Sal.Interfaces;
using TeaLightV5.Foundation.Utilities;

namespace Conference.Core.BL.Sync
{
    public abstract class SyncObject
    {
        public abstract void Update(DateTime fromDate);
    }

    public abstract class SyncObject<TDto, TE> 
        : SyncObject
        where TDto : IServiceObject, new()
        where TE : IEntity<string>, ISyncableEntity, new()
    {
        protected SyncObject(string dataContext)
        {
            
        }

        protected abstract TDto FromDatabase(TE item);

        protected abstract TE FromService(TDto item);

        public override void Update(DateTime fromDate)
        {
            SynchronizeServiceClient service = Client();

            UpdateFromServiceEntity(service, fromDate);
            UpdateFromServiceDeleted(service, fromDate);

            UpdateFromDatabaseEntity(service, fromDate);
            UpdateFromDatabaseDeleted(service, fromDate);

            BaseSyncContext.DoUpdateFinished(typeof(TE));
        }

        protected SynchronizeServiceClient Client()
        {
            return new SynchronizeServiceClient();
        }

        #region FromService

        protected abstract Collection<TDto> UpdateFromServiceEntity(SynchronizeServiceClient service, DateTime fromDate);

        protected void GetByModifiedDateCompleted(SynchronizeServiceClient service, DateTime fromDate)
        {
            try
            {
                Collection<TDto> data = UpdateFromServiceEntity(service, fromDate);
                if (data != null)
                {
                    IRepositoryBase<TE> repository = Repository.GetRepository<TE>();
                    foreach (TDto item in data)
                    {
                        try
                        {
                            TE entity = FromService(item);
                            repository.Save(entity);
                        }
                        catch (Exception ex)
                        {
                            Exceptions.Handle(ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Exceptions.Handle(ex);
            }
        }

        #endregion

        #region FromServiceDeleted

        protected abstract void UpdateFromServiceDeleted(SynchronizeServiceClient service, DateTime fromDate);

        protected void OnUpdateServiceDeletedQueryComplete(AsyncCompletedEventArgs e, Collection<Guid> result)
        {
            try
            {
                if (!e.Cancelled
                    && e.Error == null)
                {
                    IRepositoryBase<TE> repository = Repository.GetRepository<TE>();

                    foreach (Guid item in result)
                    {
                        try
                        {
                            repository.Delete(item.ToString("N"));
                        }
                        catch (Exception ex)
                        {
                            Exceptions.Handle(ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Exceptions.Handle(ex);
            }
        }

        #endregion

        #region FromDatabase

        private void UpdateFromDatabaseEntity(SynchronizeServiceClient service, DateTime fromDate)
        {
            try
            {
                IRepositoryBase<TE> repository = Repository.GetRepository<TE>();

                TableQuery<TE> query = (TableQuery<TE>)(from i in repository.GetTable()
                                                        where i.Modified >= fromDate
                                                        select i);

                Collection<TDto> list = new Collection<TDto>();
                foreach (TE item in query)
                {
                    list.Add(FromDatabase(item));
                }
                if (list.Count > 0 )
                {
                    UpdateFromDatabaseEntity(service, list);
                }
            }
            catch (Exception ex)
            {
                Exceptions.Handle(ex);
            }
        }

        protected abstract void UpdateFromDatabaseEntity(SynchronizeServiceClient data, Collection<TDto> list);

        #endregion

        #region FromDatabaseDeleted

        private void UpdateFromDatabaseDeleted(SynchronizeServiceClient service, DateTime fromDate)
        {
            try
            {
                IRepositoryBase<DeletedRow> repository = Repository.GetRepository<DeletedRow>();

                TableQuery<DeletedRow> query = (TableQuery<DeletedRow>)(from i in repository.GetTable()
                                                        where i.Modified >= fromDate
                                                        select i);

                Collection<Guid> list = new Collection<Guid>();
                foreach (DeletedRow item in query)
                {
                    list.Add(new Guid(item.RowId));
                }
                if (list.Count > 0)
                {
                    UpdateFromDatabaseDeleted(service, new DeletedRowRequest() { Data = list, IsLast = true });
                }
            }
            catch (Exception ex)
            {
                Exceptions.Handle(ex);
            }
        }

        protected abstract void UpdateFromDatabaseDeleted(SynchronizeServiceClient service, DeletedRowRequest request);


        #endregion

    }
}
